<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>块级作用域与函数声明</title>
  </head>
  <body>
    <script>
      /**
         * 下面这段代码如果在ES5环境中执行的话类似于
         * 后面呈现的那样，虽然
         *    if (false) {
                    function f() {
                        console.log("I am inside!");
                    }
        }
           但是预解析的函数f还是会被赋值成这个函数
        */

    //   function f() {
    //     console.log("I am outside!");
    //   }

    //   (function () {
    //     if (false) {//虽然这里是false里面的f函数不会执行，但是在预解析的过程中f会被赋值为function
    //       function f() {
    //         console.log("I am inside!");
    //       }
    //     }

    //     f();
    //   })();

      //   function f() {
      //     console.log("I am outside!");
      //   }

      //   (function () {
      //     function f() {
      //         console.log("I am inside!");
      //       }
      //     if (false) {

      //     }

      //     f();
      //   })();

      /**(理想状况)
       * ===但是如果在ES6环境中，在块级作用域中定义函数就相当于let===
       * 虽然f函数也会预解析，但是因为表现的像let一样(受制于块级作用域)因此下方f()访问不到它 只能访问全局的函数
       */

      /**
         * 但是由于ES6要兼容ES5,这样的函数在ES5和ES6环境中执行结果完全不同
         * 所以在ES6环境中:
         * 允许在块级作用域内声明函数。
              函数声明类似于var，即会提升到全局作用域或函数作用域的头部。
              同时，函数声明还会提升到所在的块级作用域的头部。
        */

      //在ES6中执行的过程如下
      //也就是说和ES5环境中的预解析不同的是在ES5中f被直接解析为function
      //但是在ES6中f先被预解析为undefined 然后等到代码执行到函数定义的地方再赋值为function
    //   function f() {
    //     console.log("I am outside!");
    //   }
    //   (function () {
    //     var f = undefined;
    //     if (true) {
    //       function f() {
    //         console.log("I am inside!");
    //       }
    //     }

    //     f();
    //   })();



    /**因为预解析的时候会被解析成下面那样的代码，所以在块级作用域内部 也就是{}中定义函数最好不要这样定义*/

    // {
    //     function  foo(){
    //         console.log("1111");
    //     }
    // }

    /*
     {
         var foo=undefined;

         foo=function
     }    
    */


    // 块级作用域内部，优先使用函数表达式
    {
        let user =function(){

        }
    }

    //另外，还有一个需要注意的地方。ES6 的块级作用域必须有大括号，如果没有大括号，JavaScript 引擎就认为不存在块级作用域。

// 第一种写法，报错
if (true) let x = 1;

// 第二种写法，不报错
if (true) {
  let x = 1;
}

   
    </script>
  </body>
</html>
